/**
 * Created by meiguizhinian on 2018/6/28
 * Copyright © 2018 lixiaolong. All rights reserved.
 */

//TODO：等待完成
//单例/全静态/枚举
ivy.EditorDataManager = {
	getInstance: function () {
		return this;
	},

	/**
	 * getAnimationDataBy(classID)
	 * getAnimationDataBy(fileName)
	 * */
	getAnimationDataBy : function(aniFileName) {
		if (cc.isNumber(aniFileName)) {
			aniFileName = ivy.SceneCommonDataManager.getInstance().getAniFileNameByClassID(aniFileName);
		}
		if (this.animationDatasMap_.has(aniFileName)) {
			return this.animationDatasMap_.get(aniFileName);
		} else {
			let aniFilePath = ivy.GlobleConfig.getInstance().getAnimationDataPath(aniFileName);
			let dataPtr = ivy.AnimationData.createWithFileName(aniFilePath);
			if (dataPtr) {
				this.animationDatasMap_.set(aniFileName, dataPtr);
				dataPtr.setAnimationName(aniFileName);
			}
			return dataPtr;
		}
	},

	/**
	 * SpineAnimationDataSPtr getSpineAnimationDataBy(int32_t classID);
	 * SpineAnimationDataSPtr getSpineAnimationDataBy(const std::string& fileName);
	 */
	getSpineAnimationDataBy : function(classIDOrFileName) {
		if (cc.isNumber(classIDOrFileName)) {
			classIDOrFileName = ivy.SceneCommonDataManager.getInstance().getAniFileNameByClassID(classIDOrFileName);
		}
		if (cc.isString(classIDOrFileName)) {
			let aniFileName = classIDOrFileName;
			if (this.spineAnimationDatasMap_.has(aniFileName)) {
				return this.spineAnimationDatasMap_.get(aniFileName);
			} else {
				let dataPtr = ivy.SpineAnimationData.createWithFileName(aniFileName);
				if (dataPtr) {
					this.spineAnimationDatasMap_.set(aniFileName, dataPtr);
					return dataPtr;
				}
			}
		}
		return null;
	},
	//////////////////////////////////////////////////////////////////////////
	//系统变量和任务相关数据加载接口
	initSystemVariatesAndQuestVarWithFile : function(filePath) {
		let is = new ivy.InputStream(filePath);
		if (is.empty()) {
			cc.log("LoadFile :%s Failed!", filePath);
			return;
		}
		let count = is.readJInt16();//系统变量总数
		this.systemVariates = [];
		this.systemVariatesTypes = [];
		for (let i = 0; i < count; ++i) {
			this.systemVariates[i] = 0;
			let ov = is.readInt8();
			this.systemVariatesTypes[ov] = is.readInt8();//类型
		}
		//任务相关暂时没有读取
	},
	getSystemVariateCount : function() { return this.systemVariates.length; },
	getSystemVariateValue : function(index) {
		if (index < 0 || index >= this.systemVariates.length) {
			return -1;
		}
		return this.systemVariates[index];
	},

	resetLocalLSystemVariates : function() {
		for (let i = 0; i < this.systemVariates.length; ++i) {
			if (this.systemVariatesTypes[i] >= ivy.EditorDataManager.eLOCAL_VARIATE) {
				this.systemVariates[i] = 0;
			}
		}
	},
	clearAllSystemVariates : function() {
		for (let i = 0; i < this.systemVariates.length; ++i){
			this.systemVariates[i] = 0;
		}
	},
	setSystemVariateValue : function(index, val) {
		if (index < 0 || index >= this.systemVariates.length) {
			return -1;
		}
		this.systemVariates[index] = val;
	},
	changeSystemVariateValue : function(index, val) {
		if (index < 0 || index >= this.systemVariates.length) {
			return -1;
		}
		this.systemVariates[index] += val;
	},
	//////////////////////////////////////////////////////////////////////////
	//数据编辑器数据加载接口
	initGameDataWithFile : function(filePath) {
		let file = new ivy.InputStream(filePath);
		if (file.empty) {
			cc.log("LoadFile :%s Failed!", filePath);
			return;
		}
		//加载源数量
		let dataTypeCount = file.readJInt16();
		for (let i = 0; i < dataTypeCount; ++i) {
			let typeName = file.readStringUTF8();
			let typeElementCount = file.readJInt16();

			let gdt = new ivy.EditorDataManager.GameDataType(typeName);
			for (let j = 0; j < typeElementCount; ++j) {
				let elementType = file.readJInt16();
				/* let propertyData =  */file.readJInt16();
				gdt.vecTypes.push(elementType);
				//gdt.vecTypePros_.push_back(propertyData);
			}
			this.vecDataTypes.push(gdt);
		}

		let listDataCount = file.readJInt16();

		cc.assert(listDataCount === dataTypeCount);

		let indexInMapInt = 0;
		let indexInMapString = 0;
		let indexInMapArray = 0;
		this.vecDatas = [];
		this.vecLinkDatas = [];

		let mapBaseDataInt32Temp_Use = new LLDictionary();//std::map<int32_t, int32_t >
		let mapBaseDataArrayTemp_Use = new LLDictionary(cc.pointEqualToPoint);//std::map<cocos2d::Point, int32_t>
		let mapBaseDataStringTemp_Use = new LLDictionary();//std::map<std::string, int32_t>

		for (let i = 0; i < dataTypeCount; ++i) {
			let dataCount = file.readJInt16();
			this.vecDatas[i] = [];
			this.vecLinkDatas[i] = [];
			for (let j = 0; j < dataCount; ++j) {
				let dataLinkCount = file.readJInt16();
				this.vecLinkDatas[i][j] = [];
				for (let k = 0; k < dataLinkCount; ++k) {
					let linkType = file.readJInt16();
					let linkIndex = file.readJInt16();
					let linkValue1 = file.readJInt16();
					let linkValue2 = file.readJInt16();
					this.vecLinkDatas[i][j][k * 4] = linkType;
					this.vecLinkDatas[i][j][k * 4 + 1] = linkIndex;
					this.vecLinkDatas[i][j][k * 4 + 2] = linkValue1;
					this.vecLinkDatas[i][j][k * 4 + 3] = linkValue2;
				}

				let dataElementCount = file.readJInt16();

				cc.assert(dataElementCount === this.vecDataTypes[i].vecTypes.length);
				this.vecDatas[i][j]= [];
				for (let k = 0; k < this.vecDataTypes[i].vecTypes.length; ++k) {
					switch (this.vecDataTypes[i].vecTypes[k]) {
						case ivy.EditorDataManager.BaseDataElementType.eDataString: {
							let s = file.readStringUTF8();
							if (!mapBaseDataStringTemp_Use.has(s)) {
								mapBaseDataStringTemp_Use.set(s, indexInMapString);
								this.vecDatas[i][j][k] = indexInMapString;
								this.mapBaseDataString[indexInMapString++] = s;
							} else {
								this.vecDatas[i][j][k] = mapBaseDataStringTemp_Use.get(s);
							}
							break;
						}
						case ivy.EditorDataManager.BaseDataElementType.eDataInt: {
							let intValue = file.readJInt32();
							if (!mapBaseDataInt32Temp_Use.has(intValue)) {
								mapBaseDataInt32Temp_Use.set(intValue, indexInMapInt);
								this.vecDatas[i][j][k] = indexInMapInt;
								this.mapBaseDataInt32_[indexInMapInt++] = intValue;
							} else {
								this.vecDatas[i][j][k] = mapBaseDataInt32Temp_Use.get(intValue);
							}
							break;
						}
						case ivy.EditorDataManager.BaseDataElementType.eDataTypeElement: {
							let elementTypeIndex = file.readJInt16();
							let elementIndex = file.readJInt16();
							let vec = cc.p(elementTypeIndex, elementIndex);
							if (!mapBaseDataArrayTemp_Use.has(vec)) {
								mapBaseDataArrayTemp_Use.set(vec, indexInMapArray);
								this.vecDatas[i][j][k] = (indexInMapArray);
								this.mapBaseDataArray[indexInMapArray++] = [elementTypeIndex, elementIndex];
							} else {
								this.vecDatas[i][j][k] = mapBaseDataArrayTemp_Use.get(vec);
							}
							break;
						}
						case ivy.EditorDataManager.BaseDataElementType.eDataAniAction: {
							let elementTypeIndex = file.readJInt16();
							let elementIndex = file.readJInt16();
							let vec = cc.p(elementTypeIndex, elementIndex);
							if (!mapBaseDataArrayTemp_Use.has(vec)) {
								mapBaseDataArrayTemp_Use.set(vec, indexInMapArray);
								this.vecDatas[i][j][k] = indexInMapArray;
								this.mapBaseDataArray[indexInMapArray++] = [elementTypeIndex, elementIndex];
							} else {
								this.vecDatas[i][j][k] = mapBaseDataArrayTemp_Use.get(vec);
							}
							break;
						}
						case ivy.EditorDataManager.BaseDataElementType.eDataScene:
						case ivy.EditorDataManager.BaseDataElementType.eDataAI:
						case ivy.EditorDataManager.BaseDataElementType.eDataList: {
							let intValue = file.readJInt16();
							if (mapBaseDataInt32Temp_Use.has(intValue)) {
								mapBaseDataInt32Temp_Use.set(intValue, indexInMapInt);
								this.vecDatas[i][j][k] = indexInMapInt;
								this.mapBaseDataInt32_[indexInMapInt++] = intValue;
							} else {
								this.vecDatas[i][j][k] = mapBaseDataInt32Temp_Use.get(intValue);
							}
							break;
						}
					}
				}
			}
		}
	},
	getLinkDataCount : function(type, id) {
		if (type < 0 || id < 0)
			return -1;
		if (type >= this.vecLinkDatas.length)
			return -1;
		if (id >= this.vecLinkDatas[type].length)
			return -1;
		return this.vecLinkDatas[type][id].length / 4;
	},
	getLinkDataType : function(type, id, index) {
		if (type < 0 || id < 0)
			return -1;
		if (type >= this.vecLinkDatas.length)
			return -1;
		if (id >= this.vecLinkDatas[type].length)
			return -1;
		return this.vecLinkDatas[type][id][index * 4];
	},
	getLinkDataIndex : function(type, id, index) {
		if (type < 0 || id < 0)
			return -1;
		if (type >= this.vecLinkDatas.length)
			return -1;
		if (id >= this.vecLinkDatas[type].length)
			return -1;
		return this.vecLinkDatas[type][id][index * 4 + 1];
	},
	getLinkDataValue1 : function(type, id, index) {
		if (type < 0 || id < 0)
			return -1;
		if (type >= this.vecLinkDatas.length)
			return -1;
		if (id >= this.vecLinkDatas[type].length)
			return -1;
		return this.vecLinkDatas[type][id][index * 4 + 2];
	},
	getLinkDataValue2 : function(type, id, index) {
		if (type < 0 || id < 0)
			return -1;
		if (type >= this.vecLinkDatas.length)
			return -1;
		if (id >= this.vecLinkDatas[type].length)
			return -1;
		return this.vecLinkDatas[type][id][index * 4 + 3];
	},
	getDataCountByType : function(type) {
		if (type < 0)
			return 0;
		if (type >= this.vecDatas.length)
			return 0;
		return this.vecDatas[type].length;
	},
	getElementCountByType : function(type) {
		if (type < 0)
			return 0;
		if (type >= this.vecDatas.length)
			return 0;
		if (this.vecDatas[type].length <= 0)
			return 0;
		return this.vecDatas[type][0].length;
	},

	exist : function(type, id, ele) {
		return this.rangeCheck(type, id, ele);
	},

	// template<typename... Args>
	// void get(int type, int id, Args&&... args) const
	// 	{
	// 		getImpl(type, id, std::forward<Args&&>(args)...);
	// }
	// template<typename Value = int32_t>
	// 	Value getValue(int32_t type, int32_t id, int32_t ele) const
	// 	{
	// 		if (!rangeCheck(type, id, ele))
	// return Value();
	// let const base = vecDataTypes[type].vecTypes[ele];
	// let const index = vecDatas[type][id][ele];
	// switch (base)
	// {
	// 	case BaseDataElementType::eDataInt:
	// 	case BaseDataElementType::eDataList:
	// 	case BaseDataElementType::eDataScene:
	// 	case BaseDataElementType::eDataAI:
	// 	{
	// 		const let itr = mapBaseDataInt32_.find(index);
	// 		if (itr == mapBaseDataInt32_.end())
	// 			return Value();
	// 		return itr->second;
	// 	}
	// 	default:
	// 		return Value();
	// }
	// }
	// template<typename Value = std::string>
	// const std::string& getString(int32_t type, int32_t id, int32_t ele) const
	// 	{
	// 		static std::string gs;
	// if (!rangeCheck(type, id, ele))
	// 	return gs;
	// let const base = vecDataTypes[type].vecTypes[ele];
	// let const index = vecDatas[type][id][ele];
	// switch (base)
	// {
	// 	case BaseDataElementType::eDataString:
	// 	{
	// 		const let itr = mapBaseDataString.find(index);
	// 		if (itr == mapBaseDataString.end())
	// 			return gs;
	// 		return itr->second;
	// 	}
	// 	default:
	// 		return gs;
	// }
	// }
	// template<typename Value>
	// const std::vector<Value>& getVector(int32_t type, int32_t id, int32_t ele) const
	// 	{
	// 		static_assert(sizeof(Value) == sizeof(int32_t), "sizeof error");
	// typedef std::vector<Value> ReturnType;
	// static ReturnType gs;
	// assert(gs.empty());
	// if (!rangeCheck(type, id, ele))
	// 	return gs;
	// let const base = vecDataTypes[type].vecTypes[ele];
	// let const index = vecDatas[type][id][ele];
	// switch (base)
	// {
	// 	case BaseDataElementType::eDataTypeElement:
	// 	case BaseDataElementType::eDataAniAction:
	// 	{
	// 		const let itr = mapBaseDataArray.find(index);
	// 		if (itr == mapBaseDataArray.end())
	// 			return gs;
	// 		return *static_cast<const ReturnType*>((const void*)(&itr->second));
	// 	}
	// 	default:
	// 		return gs;
	// }
	// }
	// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////private:
	rangeCheck : function(type, id, ele) {
		if (type < 0 || id < 0 || ele < 0)
			return false;
		if (type >= this.vecDatas.length)
			return false;
		if (id >= this.vecDatas[type].length)
			return false;
		if (ele >= this.vecDatas[type][id].length)
			return false;
		return true;
	},
	getData : function(type, id, elementType) {
		if (type < 0 || id < 0 || elementType < 0)
			return null;

		if (type >= this.vecDatas.length) {
			return null;
		}

		if (id >= this.vecDatas[type].length) {
			return null;
		}

		if (elementType >= this.vecDatas[type][id].length) {
			return null;
		}

		let index = this.vecDatas[type][id][elementType];
		let baseType = this.vecDataTypes[type].vecTypes[elementType];

		switch (baseType) {
			case ivy.EditorDataManager.BaseDataElementType.eDataString:
				return this.mapBaseDataString[index];
			case ivy.EditorDataManager.BaseDataElementType.eDataTypeElement:
			case ivy.EditorDataManager.BaseDataElementType.eDataAniAction:
				return this.mapBaseDataArray[index];
			case ivy.EditorDataManager.BaseDataElementType.eDataInt:
			case ivy.EditorDataManager.BaseDataElementType.eDataList:
			case ivy.EditorDataManager.BaseDataElementType.eDataScene:
			case ivy.EditorDataManager.BaseDataElementType.eDataAI:
				return this.mapBaseDataInt32_[index];
			default:
				break;
		}
		return null;
	},
	// template<typename Value, typename... Args>
	// void getImpl(int type, int id, int ele, Value& dest, Args&&... args) const
	// 	{
	// 		get(type, id, ele, dest);
	// get(type, id, std::forward<Args&&>(args)...);
	// }
	// template<typename Value, bool IsInt>
	// struct CallGetValue;
	// template<typename Value>
	// struct CallGetValue<Value, true>
	// {
	// 	static void call(const EditorDataManager& dm, int type, int id, int ele, Value& dest)
	// {
	// 	dest = dm.getValue<Value>(type, id, ele);
	// }
	// };
	// template<typename Value>
	// struct CallGetValue<Value, false>
	// {
	// 	static void call(const EditorDataManager& dm, int type, int id, int ele, Value& dest)
	// {
	// 	dest.assign(dm.getVector<Value>(type, id, ele));
	// }
	// };
	// void getImpl(int type, int id, int ele, std::string& dest) const
	// 	{
	// 		dest = getString<std::string>(type, id, ele);
	// }
	// template<typename Value>
	// void getImpl(int type, int id, int ele, std::vector<Value>& dest) const
	// 	{
	// 		dest = getVector<Value>(type, id, ele);
	// }
	// template<typename Value>
	// void getImpl(int type, int id, int ele, Value& dest) const
	// 	{
	// 		CallGetValue<Value, std::is_assignable<Value&, int>::value>::call(*this, type, id, ele, dest);
	// }
	// template<typename Value, template<typename... P> class C>
	// void getImpl(int type, int id, int ele, C<Value>& dest) const
	// 	{
	// 		const auto& t = getVector<Value>(type, id, ele);
	// dest.assign(t.begin(), t.end());
	// }
	//系统变量私有数据区
	systemVariatesTypes : [],
	systemVariates : [],
	//数据编辑器私有数据区
	vecDatas : [],
	vecLinkDatas : [],
	mapBaseDataInt32_ : {},
	mapBaseDataString : {},
	stringTable_ : {},
	mapBaseDataArray : {},
	vecDataTypes : [],
	//动画私有数据区
	animationDatasMap_ : new LLDictionary(),
	spineAnimationDatasMap_ : new LLDictionary(),
};

ivy.EditorDataManager.eSUPER_GLOBLE_VARIATE = 0;//超全局
ivy.EditorDataManager.eGLOBLE_VARIATE = 1;//全局
ivy.EditorDataManager.eLOCAL_VARIATE = 2;//局部
ivy.EditorDataManager.eOTHER_VARIATE = 3;//局部

ivy.EditorDataManager.BaseDataElementType = {
	eDataString         : 0,
	eDataInt            : 1,
	eDataTypeElement    : 2,
	eDataAniAction      : 3,
	eDataList           : 4,
	eDataScene          : 5,
	eDataAI             : 6,
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//对象 let obj = new ll.Obj(param)
(function () {
	ivy.EditorDataManager.GameDataType = function (name) {
		//成员变量
		this.name = name;
		this.vecTypes = [];
	};
	let p = ivy.EditorDataManager.GameDataType.prototype;

	p.addBaseType = function (type) {
		this.vecTypes.push(type);
	};
})();